package com.chen.sample2.common.util;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanCopier;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @desc 对象拷贝工具，注意包装类不会拆箱
 */
@Slf4j
public final class DomainUtil {
    private static Logger logger = LoggerFactory.getLogger(DomainUtil.class);
    /**
     * BeanCopier的缓存
     */
    private static final ConcurrentHashMap<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>(128);

    private DomainUtil() {
    }

    /**
     * BeanCopier的copy
     *
     * @param source 源 要复制的对象
     * @param target 目标 复制对象
     */
    public static void copy(Object source, Object target) {
        String key = genKey(source.getClass(), target.getClass());
        BeanCopier bc;
        if (BEAN_COPIER_CACHE.containsKey(key)) {
            bc = BEAN_COPIER_CACHE.get(key);
        } else {
            bc = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_CACHE.put(key, bc);
        }
        bc.copy(source, target, null);
    }


    /**
     * 复制对象,使用map缓存BeanCopier
     * BeanCopier的复制比BeanUtils快3倍
     *
     * @param source 源 要复制的对象
     * @param target 目标 复制对象的类型
     * @return 复制对象的实例
     */
    public static <T> T copy(Object source, Class<T> target){
        if (source == null || target == null) {
            return null;
        }
        String key = genKey(source.getClass(), target);
        BeanCopier bc;
        if (BEAN_COPIER_CACHE.containsKey(key)) {
            bc = BEAN_COPIER_CACHE.get(key);
        } else {
            bc = BeanCopier.create(source.getClass(), target, false);
            BEAN_COPIER_CACHE.put(key, bc);
        }

        try {
            T t = target.newInstance();
            bc.copy(source, t, null);
            return t;
        } catch (Exception e) {
            logger.error("copy error:",e);
            return null;
        }
    }

    /**
     * 复制list
     *
     * @param source 源 要复制的对象
     * @param target 目标 复制到此对象的类型
     * @return 复制对象列表的实例
     */
    public static <T, K> List<K> copyList(List<T> source, Class<K> target) {

        if (null == source || source.isEmpty()) {
            return Collections.emptyList();
        }
        return source.stream().map(e -> copy(e, target)).collect(Collectors.toList());
    }

    /**
     * 生成key
     *
     * @param srcClazz 源文件的class
     * @param tgtClazz 目标文件的class
     * @return string
     */
    private static String genKey(Class<?> srcClazz, Class<?> tgtClazz) {
        return srcClazz.getName() + tgtClazz.getName();
    }

}